package com.example.gaojt.androiddemo.statical.sdk;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import android.os.Process;
import android.util.Log;

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.zip.GZIPOutputStream;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

/**
 * Created by gaojt on 7/7/17.
 */

public class SendService {
    private static final boolean DEBUG = true;
    private static final String TAG = "SendService";
    private static final int MSG_SEND_TO_REMOTE = 1;
    private static final int MSG_LOOP = 2;
    private static final int MAX_SEND_COUNT = 5;

    private Handler sLogHandler;
    private Context mContext;
    private String mProcessName;

    public SendService(Context context, String processName) {
        mContext = context;
        mProcessName = processName;

        HandlerThread handlerThread = new HandlerThread("log network worker", Process.THREAD_PRIORITY_BACKGROUND);
        handlerThread.start();
        sLogHandler = new Handler(handlerThread.getLooper()) {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                if (msg.what == MSG_SEND_TO_REMOTE) {
                    sendToRemote();
                } else if (msg.what == MSG_LOOP) {
                    send();
                }
            }
        };
    }

    private ArrayList<MsgInfo> getSendMsgListFromDB() {

        ArrayList<MsgInfo> msgList = new ArrayList<>(MAX_SEND_COUNT);
        synchronized (LogInfoDB.LOCK) {
            LogInfoDB db = new LogInfoDB(mContext, mProcessName);
            Cursor cursor = null;
            try {
                cursor = db.query(null, "_id != 0 LIMIT " + 0 + "," + MAX_SEND_COUNT, null);
                if (cursor != null && cursor.getCount() > 0) {
                    Log.d(TAG, "getSendMsgListFromDB: cursor.getCount() = " + cursor.getCount());
                    while (cursor.moveToNext()) {
                        MsgInfo msgInfo = new MsgInfo();
                        msgInfo.log = cursor.getString(cursor.getColumnIndex(LogInfoDB.COLUMN_MSG));
                        msgInfo.id = cursor.getInt(cursor.getColumnIndex(LogInfoDB.COLUMN_ID));
                        msgList.add(msgInfo);
                    }
                }
            } catch (Exception e) {
                Log.w(TAG, "getSendMsgListFromDB: ", e);
            } finally {
                if (cursor != null) {
                    cursor.close();
                }
                db.close();
            }
        }
        return msgList;
    }

    private class MsgInfo {
        int id;
        String log;
    }

    public void send() {
        sLogHandler.removeMessages(MSG_SEND_TO_REMOTE);
        sLogHandler.sendEmptyMessage(MSG_SEND_TO_REMOTE);
    }

    private void sendToRemote() {
        // 读取数据库
        ArrayList<MsgInfo> msgList = getSendMsgListFromDB();
        Log.d(TAG, "run 1: size = " + msgList.size());
        if (msgList.size() == 0) {
            return;
        }

        boolean loop = true;
        if (msgList.size() < MAX_SEND_COUNT) {
            //说明没有足够的消息
            loop = false;

        }
        ArrayList<MsgInfo> delList = new ArrayList<MsgInfo>();
        for (MsgInfo info : msgList) {
            if (!delMsgFromDB(info)) {
                delList.add(info);
            }
        }

        Log.d(TAG, "run 2: size = " + msgList.size());
        msgList.removeAll(delList);
        StringBuilder mgs = new StringBuilder();
        for (MsgInfo info : msgList) {
            mgs.append(info.log);
            mgs.append("\n");
        }

        String sendMsg = mgs.toString();
        Log.d(TAG, "run: sendMsg = " + sendMsg);
        boolean success = sendLog(sendMsg);
        if (!success) {
            // 从新写入到数据库中备份起来
            for (MsgInfo info : msgList) {
                addMsgToDB(info);
            }
        }
        if (loop) {
            sLogHandler.sendEmptyMessage(MSG_LOOP);
        }
    }

    private void addMsgToDB(MsgInfo info) {
        synchronized (LogInfoDB.LOCK) {
            LogInfoDB db = new LogInfoDB(mContext, mProcessName);
            try {
                ContentValues values = new ContentValues();
                values.put(LogInfoDB.COLUMN_MSG, info.log);
                db.insert(values);
            } catch (Exception e) {

            } finally {
                db.close();
            }
        }
    }

    private boolean delMsgFromDB(MsgInfo info) {
        synchronized (LogInfoDB.LOCK) {
            LogInfoDB db = new LogInfoDB(mContext, mProcessName);
            try {

                int count = db.delete("_id = " + info.id, null);
                Log.d(TAG, "delMsgFromDB: count = " + count);
                if (count == 1) {
                    return true;
                }
            } catch (Exception e) {

            } finally {
                db.close();
            }
            return false;
        }
    }

    public String getUrl() {
        return "https://10.86.236.173:8089/api/cgs/log";
    }

    private boolean sendLog(String json) {
        // 使用HttpURLConnection上报
        BufferedWriter bufferedWriter = null;
        // 建立连接
        URL url;
        HttpURLConnection httpConn = null;
        try {
            url = new URL(getUrl());
            if (DEBUG) {
                Log.d(TAG, "上报url：" + getUrl());
            }
            if (url.getProtocol().toLowerCase().equals("https")) {
                HttpsURLConnection https = (HttpsURLConnection) url.openConnection();
                https.setHostnameVerifier(new HostnameVerifier() {

                    public boolean verify(String hostname, SSLSession session) {
                        return true;
                    }
                });
                SSLSocketFactory ssl = trustAllHosts();
                if (ssl != null) {
                    https.setSSLSocketFactory(ssl);
                }
                httpConn = https;
            } else {
                httpConn = (HttpURLConnection) url.openConnection();
            }
            // 设置参数
            httpConn.setDoOutput(true); // 需要输出
            httpConn.setDoInput(true); // 需要输入
            httpConn.setUseCaches(false); // 不允许缓存
            httpConn.setRequestMethod("POST"); // 设置POST方式连接
            // 设置请求属性
            httpConn.setRequestProperty("Content-Type", "gzip");
            httpConn.setRequestProperty("Content-Encoding", "gzip");
            httpConn.setRequestProperty("Connection", "Keep-Alive");// 维持长连接
            httpConn.setRequestProperty("Charset", "UTF-8");
            // 关闭连接
            httpConn.setRequestProperty("Connection", "close");
            httpConn.setConnectTimeout(20000);
            httpConn.setReadTimeout(20000);
            // 连接
            httpConn.connect();
            bufferedWriter = new BufferedWriter(
                    new OutputStreamWriter(new GZIPOutputStream(httpConn.getOutputStream()), "UTF-8"));
            bufferedWriter.write(json);
            try {
                bufferedWriter.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            int responseCode = httpConn.getResponseCode();
            if (DEBUG) {
                Log.d(TAG, "responseCode : " + responseCode);
            }
            return true;
        } catch (Throwable e) {
            if (DEBUG) {
                Log.d(TAG, "httpconn exception", e);
            }
        } finally {
            if (httpConn != null) {
                httpConn.disconnect();
            }
        }
        return false;
    }

    private SSLSocketFactory trustAllHosts() {
        TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {
            @Override
            public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            }

            @Override
            public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {

            }

            @Override
            public X509Certificate[] getAcceptedIssuers() {
                return null;
            }
        }};

        try {
            SSLContext sc = SSLContext.getInstance("TLS");
            sc.init(null, trustAllCerts, null);
            return sc.getSocketFactory();
        } catch (Throwable e) {
            if (DEBUG) {
                Log.w(TAG, "trustAllHosts: ", e);
            }
        }
        return null;
    }


}
